解構賦值是ES6新增的寫法,讓我們更快捷去把陣列或物件裏的值賦予給變數,同時也讓程式碼更易閱讀。解構賦值的概念挺直接的,但自己在應用上還是很不熟悉,所以今天就來學習一下解構賦值的概念和應用。
為什麼ES6會新增解構賦值(Destructuring assignment)的寫法呢?因為在這之前,我們可能要用迭代或迴圈的方式去賦值,程式碼就會變長,而且可讀性較低。例如:
let a = 1;
let b = 2;
let c = 3;
const num = [10,20,30]
const myNum = [a,b,c]
for(i=0; i<num.length; i++){
myNum[i] = num[i]
}
console.log(myNum) //[10,20,30]
所以ES6新增了解構賦值的寫法,那麼它到底是什麼意思呢?看看MDN頭一段的解釋:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
我們可以把這個詞拆開來想:變成「解構」、「賦值」。「解構」在陣列或物件裏的值,「賦值」給變數。過程就像一個鏡子,把右邊的值,映照到左邊的變數去。
舉個簡單例子:
const city = ['Hong Kong', 'Taipei', 'Tokyo', 'Seoul']
const [cityA, cityB, cityC, cityD] = city
console.log(cityA, cityB, cityC, cityD) // Hong Kong Taipei Tokyo Seoul
以上範例可見,右邊city
陣列裏面的值,會順序地賦予給左邊的陣列裏的值。用解構賦值的方式,讓我們只用一行程式碼就完成了賦值的動作。
以下是一些陣列解構賦值(Array destructuring)用法例子:
//1.最簡單用法
const [cityA, cityB] = ['Hong Kong','Taipei']
//cityA = Hong Kong, cityB = Taipei
//2.遇上空的變數時,右邊相應的值會被跳過
[cityA, ,cityC] = ['Tokyo', 'Seoul', 'BangKok']
//cityA = Tokyo, cityC = BangKok
//3.左方多於右方,多出來的值會是undefined
[cityA, , , ,cityE] = ['Tokyo','Seoul']
//cityA = Tokyo, cityE = undefined
//4.同時交換變數
let cityA = 'Taipei';
let cityB = 'Hong Kong';
[cityA, cityB] = [cityB, cityA];
//cityA = Hong Kong, cityB = Taipei
//5.把字串解構成一個個字元,賦值到變數
const [a,b,c,d,e] = 'Tokyo'
// a = 'T', b = 'o', c = 'k', d = 'y', e = 'o'
//6. 其餘運算子
const [cityA,...cityB] = ['Seoul','Taipei','Hong Kong','BangKok'];
//city A = 'Seoul', city B = ['Taipei','Hong Kong','BangKok']
//7. 多維陣列
const [a, [b, [c,d] ]] = [1, [2, [[3,4],5] ]];
//a = 1, b = 2, c = [3,4], d = 5
陣列的解構賦值用法很直接,較特別的例子是其餘運算子的例子,其餘運算子會集合所有餘下的值成為陣列。
物件的解構賦值(Object destructuring)與陣列是相同,都是用鏡子的概念。差異在於我們會對應物件的屬性去賦值,而非像陣列那樣,對應索引值去順序賦值。例如我們有一個叫user的物件:
//例如我們有一個叫user的物件
const user = {
name: 'Tom',
age: 18
}
//解構賦值寫法。把user物件的name和age屬性值,賦予到對應的變數
const {name,age} = user //name = Tom, age = 18
//解構賦值出現之前的寫法
const name = user.name //name = Tom
const age = user.age //age = 18
注意,物件的解構賦值沒有次序之分,只要有變數的名稱與該物件的鍵(key)名稱相同,就會被賦值,如果不相同,該變數就會變成undefined
:
//如果變數名稱與鍵(key)不相同,該變數就會是undefined
const {y,name} = user // y = undefined, name = Tom
我們當然也可以自訂變數的名稱:
//重新賦予變數名稱為x和y
const {name:x, age:y} = user
// x = Tom, y = 18
拿取物件的屬性值,賦予到變數裏:
//拿取user屬性的值,賦予到變數裏
const {name:name, age:age} = user
//name = Tom, age = 18
//或者拿取user屬性的值,賦予到自訂名稱的變數(valA,valB)裏
const {name:valA, age:valB} = user
//valA = Tom, valB = 18
其餘運算子的例子:
const {name,age,city,...rest} = {name: 'Tom', age: 18, gender:'male', city: 'Taipei', pet: 'dog'}
//name = Tom
//age = 18
//city = Taipei
//rest = {gender: "male", pet: "dog"}
另外需要注意{}的前面沒有宣告字詞(var
、let
、const
),就會被當作區塊(block),而非物件的意思。例如以下的例子我們要加上括號:
//報錯寫法
{val1,val2} = {val1: 10, val2: 20};
//正確寫法
({val1,val2} = {val1: 10, val2: 20});
// val1 = 10, val2 = 20
如果有一個陣列包有物件,或者物件包有陣列,我們要拿它來做解構賦值,該怎樣做呢?其實原理是一樣:
const user = {
name: 'Amy',
age: 30,
pet: ['cat','dog','bird','fish']
}
const {name: x, age:y, pet:[val1, ,val3]} = user
console.log(x,y,val1,val3) //Amy, 30, cat, bird
陣列包物件:
const user = [
'Ken',
{pet: ['cat',['dogA','dogB']]},
100
]
const [a,b,c] = user
console.log(a) //Ken
console.log(b) //{pet: ['cat',['dogA','dogB']]}
console.log(c) //100
剛才提及,有些情況下進行解構賦值後,該變數的值會是undefined
,例如左方多右方的數值多,多出來的變數會成為undefined
。但我們可以在右方預設變數的值來避免這個情況,例如:
let [name = 'Fiona', age = 24] = ['David']
//name = David, age = 24
let {food = 'banana', color = 'yellow'} = {color: 'red'}
//food = banana, color = red
greet預設值是'Nice to meet you'。如果傳入函式的物件裏沒有greet屬性,greet就會是'Nice to meet you':
function greet({name, greet = 'Nice to meet you'}){
console.log(`${greet}, ${name}`)
}
greet( {name:'Katy', greet:'Hi'}) //Hi, Katy
greet( {name:'John'}) //Nice to meet you, John
greet({}) //Nice to meet you, undefined
greet({greet:'Good morning'}) //Good morning, undefined
其餘運算子例子:
function person({name,university,language = 'English'},...skills){
console.log(`Name: ${name}, University: ${university}, Language ${language}, Skills: ${skills}`)
}
person({name:'Mary',university:true},'JavaScript','Ruby','PHP')
//Name: Mary, University: true, Language English, Skills: JavaScript,Ruby,PHP
person({name:'Tom',university:false,language:'Mandarin'},'C','JavaScript','PHP')
//Name: Tom, University: false, Language Mandarin, Skills: C,JavaScript,PHP
高階函式的例子:
同上面的原理一樣,num預設值是'unknown',如果傳入的物件沒有num屬性,num就會是'unknown'
const list = [{name: 'Eva'},{name: 'Carrie', num:23},{name:'Olivia'}]
list.forEach( ({name, num = 'unknown'}) => console.log(`Hi I'm ${name}. My number is ${num}.`))
//Hi I'm Eva. My number is unknown.
//Hi I'm Carrie. My number is 23.
//Hi I'm Olivia. My number is unknown.
從ES6開始的JavaScript學習生活 - 解構賦值
鐵人賽:ES6 解構賦值